#include "ReadSenser.h"
#include "math.h"

//
#include "stm32f1xx_hal.h"
#include "dma.h"
#include "usart.h"

#define USE_UART huart1
#define TIMEOUT 1000
//
#define CommandLen 8 // 指令的长度
static uint8_t RawDataString[16] = {0};

// 0x03
#define ServiceAddress  0x00 // 从机地址
#define ServiceBaud     0x01 // 从机波特率
#define ServiceUnit     0x02 // 从机测量单位
#define ServiceDot      0x03 // 从机测量小数点
#define ServiceData     0x04 // 从机测量输出值
#define ServiceZero     0x05 // 变送器量程零点
#define ServiceMax      0x06 // 变送器量程满点
#define ServiceDelta    0x0c // 变送器零位偏移值

#define Mpa2kgfpcm 10.19716212978

static uint8_t ReadCommandString[CommandLen] = {0x01, 0x03, 0x00, 0x04, 0x00, 0x01}; // 读命令字符串
static const uint8_t ReadADCCommandString[CommandLen] = {0x02, 0x03, 0x00, 0x00, 0x00, 0x01, 0x84, 0x39}; // 读ADC字符串

static DataStr_s DefaultData = {
    .address = 0x00,
    .unit = Mpa_e,
    .dot = xdxxx,
    .type = Type_gauge,
    .rawData = 0,
};

static DataStr_s ADCData = {
    .address = 0x02,
    .unit = Voltage,
    .dot = xdxxx,
    .type = Type_gauge,
    .rawData = 0,
};

float SensorFloatData = 0;

typedef union _U16Union
{
    uint16_t u16;
    uint8_t u8[2];
} U16Union;

static void UARTTransmit(uint8_t *data, uint16_t size)
{
    HAL_UART_Transmit_DMA(&USE_UART, data, size);
}

static void UARTReceive()
{
    HAL_UARTEx_ReceiveToIdle_DMA(&USE_UART, RawDataString, sizeof(RawDataString));
    __HAL_DMA_DISABLE_IT(huart1.hdmarx, DMA_IT_HT);
}

/**
 * @brief 阻塞式串口发送
 *
 * @param data
 * @param size
 * @return uint8_t 1成功0失败
 */
static uint8_t UARTTransmit_Blocking(uint8_t *data, uint16_t size)
{
    if (HAL_UART_Transmit(&USE_UART, data, size, TIMEOUT) == HAL_OK)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

/**
 * @brief 阻塞式串口接收
 *
 * @return uint8_t 1成功0失败
 */
static uint8_t UARTReceive_Blocking()
{
    if (HAL_UART_Receive(&USE_UART, RawDataString, 7, TIMEOUT) == HAL_OK)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

/**
 * @brief 计算CRC16
 *
 * @param ptr
 * @param len
 * @return uint16_t
 */
uint16_t CaculateCRC16(uint8_t ptr[], uint16_t len)
{
    uint16_t crc = 0xFFFF;
    uint8_t i = 0;
    while (len--)
    {
        crc ^= *ptr++;
        for (i = 0; i < 8; ++i)
        {
            if (crc & 1)
                crc = (crc >> 1) ^ 0xA001;
            else
                crc = (crc >> 1);
        }
    }

    return crc;
}

/**
 * @brief 添加CRC16到指定长字符串
 *
 * @param cmd
 * @param len 输出的字符串长度
 * @return uint8_t*
 */
uint8_t *AddCRC16(uint8_t ptr[], uint16_t len)
{
    U16Union crc;
    crc.u16 = CaculateCRC16(ptr, len - 2);
    ptr[len - 2] = crc.u8[0];
    ptr[len - 1] = crc.u8[1];
    return ptr;
}

/**
 * @brief 添加CRC16到指令字符串末尾
 *
 * @param cmd
 * @return uint8_t*
 */
uint8_t *AddCRC16ToCommand(uint8_t cmd[])
{
    return AddCRC16(cmd, CommandLen);
}

/***/
uint8_t *BuildReadCommandString(uint8_t type)
{
    ReadCommandString[3] = type;
    return AddCRC16ToCommand(ReadCommandString);
}

static uint8_t UnpackData(DataStr_s * data, uint8_t str[], uint8_t type)
{
    U16Union u16u;
    if (str[0] == 0x01) // 压力表
    {
        data->address = str[0]; // 地址
        if (str[1] == 0x03)     // 读命令的返回值
        {
            // 由于0x03只有数据长度为2的一种情况
            u16u.u16 = CaculateCRC16(str, 5);
            if (u16u.u8[0] == str[5] && u16u.u8[1] == str[6])
            {
                u16u.u8[0] = str[4];
                u16u.u8[1] = str[3];
                // 对数据进行覆写
                switch (type)
                {
                case ServiceUnit:
                    data->unit = u16u.u16;
                    break;
                case ServiceDot:
                    data->dot = u16u.u16;
                    break;
                case ServiceData:
                    data->rawData = u16u.u16;
                    break;
                default:
                    break;
                }

                // 存在Data内的数据为Mpa单位
                data->data = (float)data->rawData / pow(10, data->dot);

                // 存在SensorFloatData内的数据为kgf/cm2单位
                SensorFloatData = (float)data->data * Mpa2kgfpcm; // 防止出现危险操作

                return 1;
            }
            else
            {
                return 0;
            }
        }

        if (str[1] == 0x06) // 写命令的返回值，不用解包
        {
            return 0;
        }

        if (str[1] == 0x80) // 异常
        {
            return 0;
        }
    }

    if (str[0] == 0x02) // ADC
    {
        data->address = str[0]; // 地址
        if (str[1] == 0x03)     // 读命令的返回值
        {
            // 由于0x03只有数据长度为2的一种情况
            u16u.u16 = CaculateCRC16(str, 5);
            if (u16u.u8[0] == str[5] && u16u.u8[1] == str[6])
            {
                u16u.u8[0] = str[4];
                u16u.u8[1] = str[3];
                // 对数据进行覆写
                data->rawData = u16u.u16;

                data->data = (float)data->rawData / pow(10, data->dot);

                return 1;
            }
            else
            {
                return 0;
            }
        }
    }

    return 0;
}

/**
 * @brief UART DMA接收完一帧数据的回调
 *
 */
void UARTReceiveCallback(void)
{
    // DMA调用时只作为Data读取
    switch (RawDataString[0])
    {
    case 0x01:
        UnpackData(&DefaultData, RawDataString, ServiceData);
        break;
    case 0x02:
        UnpackData(&ADCData, RawDataString, ServiceData);
        break;
    default:
        UnpackData(&DefaultData, RawDataString, ServiceData);
        break;
    }
}

/**
 * @brief 循环读取的回调，10Hz调用频率
 *
 */
void ReadSenserCycleCallback(void)
{
    static uint8_t count = 0;
    if (count)
    {
        UARTTransmit(ReadADCCommandString, CommandLen);
    }
    else
    {
        // 由于初始化后的数据包就是需要的数据包
        UARTTransmit(ReadCommandString, CommandLen);
    }
    count ^= 0x01;
    UARTReceive();
}

void ReadADCCycleCallback(void)
{
    UARTTransmit(ReadADCCommandString, CommandLen);
    UARTReceive();
}

/**
 * @brief 获取单位转换后的传感器参数值（kgf/cm）
 *
 * @return float
 */
float ReadSenserData_float(void)
{
    return SensorFloatData;
}

float ReadADCData_float(void)
{
    return ADCData.data;
}

/**
 * @brief 初始化压力变送器
 *
 */
void PressureSenserInit(void)
{
    // 应确保UART已经初始化
    // // 数据读取一次
    // HAL_Delay(50);
    // if (!UARTTransmit_Blocking(BuildReadCommandString(ServiceData), CommandLen))
    //     return;
    // if (!UARTReceive_Blocking())
    //     return;
    // if (!UnpackData(&DefaultData, RawDataString, ServiceData))
    //     return;
    // // 单位的读取
    // HAL_Delay(50);
    // if (!UARTTransmit_Blocking(BuildReadCommandString(ServiceUnit), CommandLen))
    //     return;
    // if (!UARTReceive_Blocking())
    //     return;
    // if (!UnpackData(&DefaultData, RawDataString, ServiceUnit))
    //     return;
    // // 小数点的读取
    // HAL_Delay(50);
    // if (!UARTTransmit_Blocking(BuildReadCommandString(ServiceDot), CommandLen))
    //     return;
    // if (!UARTReceive_Blocking())
    //     return;
    // if (!UnpackData(&DefaultData, RawDataString, ServiceDot))
    //     return;
    // 数据读取一次
    HAL_Delay(50);
    if (!UARTTransmit_Blocking(BuildReadCommandString(ServiceData), CommandLen))
        return;
    if (!UARTReceive_Blocking())
        return;
    if (!UnpackData(&DefaultData, RawDataString, ServiceData))
        return;
    // 就绪之后开启DMA读取
    HAL_Delay(50);
    UARTTransmit(BuildReadCommandString(ServiceData), CommandLen);
    UARTReceive();
}
